package com.todo.strategy.offline.application.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.todo.common.common.entity.response.BizResponse;
import com.todo.common.common.entity.response.page.PageResult;
import com.todo.common.common.enums.BizErrorCodeEnum;
import com.todo.common.common.exception.BizException;
import com.todo.common.utils.TodoCommonUtils;
import com.todo.component.redis.RedisService;
import com.todo.strategy.common.constant.StrategyOfflineKeyBuild;
import com.todo.strategy.common.enums.PlanRelationSceneEnum;
import com.todo.strategy.common.enums.StrategyStatusEnum;
import com.todo.strategy.offline.application.convert.StrategyConvert;
import com.todo.strategy.offline.application.entity.bo.PlatformStrategyBO;
import com.todo.strategy.offline.application.entity.bo.PlatformStrategyDetailBO;
import com.todo.strategy.offline.application.entity.bo.PlatformStrategyExtendBO;
import com.todo.strategy.offline.application.entity.condition.PlatformStrategyConditionBO;
import com.todo.strategy.offline.application.mq.entity.PlatformStatusChangeEntity;
import com.todo.strategy.offline.application.mq.sender.PStrategyMqSender;
import com.todo.strategy.offline.application.remote.StrategyPipelineRemoteService;
import com.todo.strategy.offline.application.service.PlanRelationService;
import com.todo.strategy.offline.application.service.PlatformStrategyService;
import com.todo.strategy.offline.infrastructure.entity.condition.PlatformStrategyCondition;
import com.todo.strategy.offline.infrastructure.entity.po.PlatformStrategyDetailPO;
import com.todo.strategy.offline.infrastructure.entity.po.PlatformStrategyPO;
import com.todo.strategy.offline.infrastructure.repository.PlatformStrategyRepository;
import com.todo.strategy.pipeline.common.enums.OperateActionEnum;
import com.todo.strategy.pipeline.common.enums.StrategyActionEnum;
import com.todo.strategy.pipeline.service.api.request.OfflineToOnlineRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * (PlatformStrategy)表服务实现类
 *
 * @author zhangwenxiang
 * @since 2024-03-04 00:19:47
 */
@Slf4j
@Service("platformStrategyService")
public class PlatformStrategyServiceImpl implements PlatformStrategyService {

    @Value("${strategy.default.examine:false}")
    private final Boolean defaultExamine = false;

    @Resource
    private PlatformStrategyRepository platformStrategyRepository;
    @Resource
    private PlanRelationService planRelationService;
    @Resource
    private RedisService redisService;
    @Resource
    private PStrategyMqSender strategyMqSender;
    @Resource
    private StrategyPipelineRemoteService strategyPipelineRemoteService;


    @Override
    public Boolean insertPlatformStrategyInfo(PlatformStrategyBO platformStrategyBO) {
        if (platformStrategyBO == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        if (!platformStrategyBO.baseCheck()) {
            log.error("PlatformStrategyService#insertPlatformStrategyInfo 新增平台攻略信息失败，数据基础校验未通过 platformStrategyBO：【{}】", JSONObject.toJSONString(platformStrategyBO));
            return false;
        }
        //一些默认新增字段赋值
        //平台数据保存默认走提交状态
        platformStrategyBO.setStatus(StrategyStatusEnum.POSTED);
        platformStrategyBO.setReferenceCount(0);
        platformStrategyBO.setViewCount(0);
        platformStrategyBO.setLikeCount(0);
        platformStrategyBO.setCollectCount(0);
        PlatformStrategyPO platformStrategyPO = StrategyConvert.convertToPlatformStrategyPO(platformStrategyBO);
        Boolean insertResult = platformStrategyRepository.insertPlatformStrategyInfo(platformStrategyPO);
        if (insertResult) {
            //增加新增标识，用于后续逻辑区分是否新增信息，默认存储7d
            redisService.set(StrategyOfflineKeyBuild.pStrategyInsertTagKey(platformStrategyPO.getId()), "ok", 7 * 24 * 60 * 60);
            if (!defaultExamine) {
                updatePlatformStrategyStatus(platformStrategyPO.getId(), StrategyStatusEnum.AUTO_EXAMINE_FAILED);
            } else {
                doSendPlatformStatusMQ(platformStrategyPO.getId(), StrategyStatusEnum.POSTED);
            }
        }
        return insertResult;
    }

    @Override
    public Boolean insertPlatformStrategyExtend(PlatformStrategyExtendBO platformStrategyExtendBO) {
        if (platformStrategyExtendBO == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        PlatformStrategyBO platformStrategyBO = queryPlatformStrategyInfoById(platformStrategyExtendBO.getStrategyId());
        if (platformStrategyBO == null) {
            log.warn("PlatformStrategyService#insertPlatformStrategyExtend 新增平台攻略扩展信息失败，查询攻略信息数据为空 platformStrategyBO：【{}】", JSONObject.toJSONString(platformStrategyBO));
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST);
        }

        if (platformStrategyBO.getStatus().equals(StrategyStatusEnum.PUBLISHED) || platformStrategyBO.getStatus().equals(StrategyStatusEnum.EXAMINING)) {
            log.warn("PlatformStrategyService#insertPlatformStrategyExtend 新增平台攻略扩展信息失败，当前攻略状态禁止操作 platformStrategyBO：【{}】", JSONObject.toJSONString(platformStrategyBO));
            throw new BizException(BizErrorCodeEnum.STRATEGY_STATUS_OPERATE_PROHIBITED);
        }
        PlatformStrategyDetailPO platformStrategyDetailPO = StrategyConvert.convertToPlatformStrategyDetailPO(platformStrategyExtendBO);
        Boolean insertResult = platformStrategyRepository.insertPlatformStrategyDetail(platformStrategyDetailPO);
        if (insertResult) {
            String redisKey = StrategyOfflineKeyBuild.strategyPlatformExtendKey(platformStrategyDetailPO.getId());
            redisService.setOneDay(redisKey, JSONObject.toJSONString(platformStrategyExtendBO));
        }
        return insertResult;
    }

    @Override
    public Boolean updatePlatformStrategyInfo(PlatformStrategyBO platformStrategyBO) {
        if (platformStrategyBO == null || platformStrategyBO.getStrategyId() == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        if (!platformStrategyBO.baseCheck()) {
            log.error("PlatformStrategyService#updatePlatformStrategyInfo 更新平台攻略信息失败，数据基础校验未通过 platformStrategyBO：【{}】", JSONObject.toJSONString(platformStrategyBO));
            return false;
        }
        PlatformStrategyBO alreadyData = queryPlatformStrategyInfoById(platformStrategyBO.getStrategyId());
        if (alreadyData == null) {
            log.error("PlatformStrategyService#updatePlatformStrategyInfo 更新平台攻略信息失败，根据主键查询数据为空 默认不操作 platformStrategyBO：【{}】", JSONObject.toJSONString(platformStrategyBO));
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST);
        }
        if (alreadyData.getStatus().equals(StrategyStatusEnum.PUBLISHED) || alreadyData.getStatus().equals(StrategyStatusEnum.EXAMINING)) {
            log.warn("PlatformStrategyService#updatePlatformStrategyInfo 更新平台攻略信息失败，当前攻略状态禁止操作 当前数据：【{}】", JSONObject.toJSONString(alreadyData));
            throw new BizException(BizErrorCodeEnum.STRATEGY_STATUS_OPERATE_PROHIBITED);
        }
        platformStrategyBO.setStatus(StrategyStatusEnum.POSTED);
        PlatformStrategyPO platformStrategyPO = StrategyConvert.convertToPlatformStrategyPO(platformStrategyBO);
        Boolean updateResult = platformStrategyRepository.updatePlatformStrategyInfo(platformStrategyPO);
        if (updateResult) {
            if (!defaultExamine) {
                updatePlatformStrategyStatus(platformStrategyPO.getId(), StrategyStatusEnum.AUTO_EXAMINE_FAILED);
            } else {
                doSendPlatformStatusMQ(platformStrategyPO.getId(), StrategyStatusEnum.POSTED);
            }
        }
        return updateResult;
    }

    @Override
    public Boolean updatePlatformStrategyExtend(PlatformStrategyExtendBO platformStrategyBO) {
        if (platformStrategyBO == null || platformStrategyBO.getStrategyId() == null) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        PlatformStrategyBO alreadyData = queryPlatformStrategyInfoById(platformStrategyBO.getStrategyId());
        if (alreadyData == null) {
            log.error("PlatformStrategyService#updatePlatformStrategyExtend 更新平台攻略详情失败，根据主键查询数据为空 默认不操作 platformStrategyBO：【{}】", JSONObject.toJSONString(platformStrategyBO));
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST);
        }
        if (alreadyData.getStatus().equals(StrategyStatusEnum.PUBLISHED) || alreadyData.getStatus().equals(StrategyStatusEnum.EXAMINING)) {
            log.warn("PlatformStrategyService#updatePlatformStrategyExtend 更新平台攻略详情失败，当前攻略状态禁止操作 当前数据：【{}】", JSONObject.toJSONString(alreadyData));
            throw new BizException(BizErrorCodeEnum.STRATEGY_STATUS_OPERATE_PROHIBITED);
        }
        PlatformStrategyDetailPO platformStrategyDetailPO = StrategyConvert.convertToPlatformStrategyDetailPO(platformStrategyBO);
        Boolean updateResult = platformStrategyRepository.updatePlatformStrategyDetail(platformStrategyDetailPO);
        if (updateResult) {
            String redisKey = StrategyOfflineKeyBuild.strategyPlatformExtendKey(platformStrategyDetailPO.getId());
            redisService.del(redisKey);
        }
        return updateResult;
    }

    @Override
    public PlatformStrategyBO queryPlatformStrategyInfoById(Long strategyId) {
        if (strategyId == null || strategyId < 0) {
            return null;
        }
        String redisKey = StrategyOfflineKeyBuild.strategyPlatformDetailKey(strategyId);
        PlatformStrategyBO alreadyData = JSONObject.parseObject(redisService.get(redisKey), PlatformStrategyBO.class);
        if (alreadyData != null) {
            return alreadyData;
        }

        PlatformStrategyPO platformStrategyPO = platformStrategyRepository.queryBasePlatformStrategyById(strategyId);
        PlatformStrategyBO platformStrategyBO = StrategyConvert.convertToPlatformStrategyBO(platformStrategyPO);
        if (platformStrategyBO == null) {
            return null;
        }
        redisService.set8H(redisKey, JSONObject.toJSONString(platformStrategyBO));
        return platformStrategyBO;
    }

    @Override
    public PlatformStrategyExtendBO queryPlatformStrategyExtendById(Long strategyId) {
        if (strategyId == null || strategyId < 0) {
            return null;
        }
        String redisKey = StrategyOfflineKeyBuild.strategyPlatformExtendKey(strategyId);
        PlatformStrategyExtendBO alreadyData = JSONObject.parseObject(redisService.get(redisKey), PlatformStrategyExtendBO.class);
        if (alreadyData != null) {
            return alreadyData;
        }

        PlatformStrategyDetailPO platformStrategyDetailPO = platformStrategyRepository.queryPlatformStrategyDetailById(strategyId);
        PlatformStrategyExtendBO platformStrategyExtendBO = StrategyConvert.convertToPlatformStrategyExtendBO(platformStrategyDetailPO);
        if (platformStrategyExtendBO == null) {
            return null;
        }
        redisService.set8H(redisKey, JSONObject.toJSONString(platformStrategyExtendBO));
        return platformStrategyExtendBO;
    }

    @Override
    @Transactional
    public Boolean removePlatformStrategyInfoById(Long strategyId) {
        if (strategyId == null || strategyId < 0) {
            throw new BizException(BizErrorCodeEnum.PARAM_ERROR);
        }
        PlatformStrategyBO platformStrategyBO = queryPlatformStrategyInfoById(strategyId);
        if (platformStrategyBO == null) {
            return true;
        }
        Boolean removed = platformStrategyRepository.removePlatformStrategyById(strategyId);
        if (removed) {
            //删除关联、拓展信息
            Boolean updated = planRelationService.removePlanRelationByBizId(strategyId, PlanRelationSceneEnum.PLATFORM_STRATEGY);
            if (updated) {
                //删除缓存、es
                String extendKey = StrategyOfflineKeyBuild.strategyPlatformExtendKey(strategyId);
                String detailKey = StrategyOfflineKeyBuild.strategyPlatformDetailKey(strategyId);
                redisService.del(extendKey);
                redisService.del(detailKey);
                //同步删除数据信息
                OfflineToOnlineRequest removeRequest = new OfflineToOnlineRequest();
                removeRequest.setBusinessId(strategyId);
                //唯一标识 攻略id+更新时间hash 注：后续如果新增版本概念可以通过id+version确认
                removeRequest.setUniKey(TodoCommonUtils.buildStriHashKey(strategyId, new Date()));
                removeRequest.setStrategyActionEnum(StrategyActionEnum.PLATFORM_STRATEGY);
                removeRequest.setOperateActionEnum(OperateActionEnum.REMOTE);
                removeRequest.setOriginData(new JSONObject().toJSONString());
                BizResponse<Boolean> bizResponse = strategyPipelineRemoteService.offlineToOnlineAsync(removeRequest);
                if (bizResponse == null || !bizResponse.isSuccess() || !bizResponse.getData()) {
                    log.error("PlatformStrategyService#removePlatformStrategyInfoById 平台攻略删除状态处理失败，数据同步失败 strategyId:{}", strategyId);
                }
            }
        }
        return removed;
    }

    @Override
    public PlatformStrategyDetailBO queryPlatformStrategyDetailById(Long strategyId) {
        if (strategyId == null || strategyId < 0) {
            return null;
        }
        PlatformStrategyBO platformStrategyBO = queryPlatformStrategyInfoById(strategyId);
        if (platformStrategyBO == null) {
            return null;
        }
        PlatformStrategyExtendBO platformStrategyExtendBO = queryPlatformStrategyExtendById(strategyId);
        PlatformStrategyDetailBO platformStrategyDetailBO = new PlatformStrategyDetailBO();
        platformStrategyDetailBO.setPlatformStrategyBO(platformStrategyBO);
        platformStrategyDetailBO.setPlatformStrategyExtendBO(platformStrategyExtendBO);

        return platformStrategyDetailBO;
    }

    @Override
    public PageResult<PlatformStrategyBO> queryPlatformStrategyByCondition(PlatformStrategyConditionBO platformStrategyConditionBO) {
        if (platformStrategyConditionBO == null) {
            return PageResult.of(Lists.newArrayList(), 0, 0, 0L);
        }
        PlatformStrategyCondition condition = StrategyConvert.convertToPlatformStrategyCondition(platformStrategyConditionBO);
        PageResult<PlatformStrategyPO> pageResult = platformStrategyRepository.queryPlatformStrategyPOByCondition(condition);
        if (pageResult == null) {
            return PageResult.of(Lists.newArrayList(), platformStrategyConditionBO.getPageIndex(), platformStrategyConditionBO.getPageSize(), 0L);
        }
        PageResult<PlatformStrategyBO> result = new PageResult<>();
        result.setResults(pageResult.getResults() == null ? null : pageResult.getResults().stream().map(StrategyConvert::convertToPlatformStrategyBO).collect(Collectors.toList()));
        result.setPageCount(pageResult.getPageCount());
        result.setPageNum(pageResult.getPageNum());
        result.setPageSize(pageResult.getPageSize());
        result.setHasNext(pageResult.isHasNext());
        result.setCurrentIndex(pageResult.getCurrentIndex());
        result.setTotal(pageResult.getTotal());
        return result;
    }

    @Override
    public List<PlatformStrategyBO> queryPlatformStrategyInfoByIdList(List<Long> strategyIdList) {
        if (CollectionUtils.isEmpty(strategyIdList)) {
            return Lists.newArrayList();
        }
        List<PlatformStrategyBO> result = new ArrayList<>();
        List<Long> missedData = new ArrayList<>();
        for (Long strategyId : strategyIdList) {
            String key = StrategyOfflineKeyBuild.strategyPlatformDetailKey(strategyId);
            PlatformStrategyBO alreadyData = JSONObject.parseObject(redisService.get(key), PlatformStrategyBO.class);
            if (alreadyData != null) {
                result.add(alreadyData);
            } else {
                missedData.add(strategyId);
            }
        }

        List<PlatformStrategyPO> platformStrategyPOList = platformStrategyRepository.queryPlatformStrategyByIdList(missedData);
        List<PlatformStrategyBO> collect = platformStrategyPOList.stream()
                .map(StrategyConvert::convertToPlatformStrategyBO)
                .collect(Collectors.toList());
        result.addAll(collect);
        collect.forEach(item -> {
            redisService.setOneDay(StrategyOfflineKeyBuild.strategyPlatformDetailKey(item.getStrategyId()), JSONObject.toJSONString(item));
        });
        return result;
    }

    @Override
    public Boolean updatePlatformStrategyStatus(Long strategyId, StrategyStatusEnum statusEnum) {
        if (strategyId == null || statusEnum == null) {
            return false;
        }
        PlatformStrategyBO platformStrategyBO = queryPlatformStrategyInfoById(strategyId);
        if (platformStrategyBO == null) {
            log.error("PlatformStrategyService#updatePlatformStrategyStatus 更新平台攻略状态失败，根据主键查询数据为空 默认不操作 strategyId：【{}】", strategyId);
            throw new BizException(BizErrorCodeEnum.DATA_NOT_EXIST);
        }
        if (platformStrategyBO.getStatus().equals(StrategyStatusEnum.DISCARD)) {
            log.error("StrategyInfoService#updateStrategyStatus 更新攻略状态失败 已废弃的状态无法操作 strategyId:{}", strategyId);
            throw new BizException(BizErrorCodeEnum.STRATEGY_STATUS_OPERATE_PROHIBITED);
        }
        if (platformStrategyBO.getStatus().equals(statusEnum)) {
            log.info("PlatformStrategyService#updatePlatformStrategyStatus 更新平台攻略状态完成，当前状态与数据状态一致，默认不操作 platformStrategyBO：【{}】", JSONObject.toJSONString(platformStrategyBO));
            return true;
        }
        Boolean updated = platformStrategyRepository.updatePlatformStrategyStatus(strategyId, statusEnum);
        if (updated) {
            // 只更新状态
            String redisKey = StrategyOfflineKeyBuild.strategyPlatformDetailKey(strategyId);
            redisService.del(redisKey);
            doSendPlatformStatusMQ(strategyId, statusEnum);
        }
        return updated;
    }

    private void doSendPlatformStatusMQ(Long strategyId, StrategyStatusEnum currentStatus) {
        PlatformStatusChangeEntity entity = new PlatformStatusChangeEntity();
        entity.setStrategyId(strategyId);
        entity.setCurrentStatus(currentStatus);
        strategyMqSender.sendPStrategyStatusChange(entity, 0);
        log.info("PlatformStrategyService#doSendPlatformStatusMQ 发送攻略状态变更消息，id：【{}】，currentStatus：【{}】", strategyId, currentStatus);
    }
}
